
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <arpa/inet.h>  
#include <netinet/in.h>  
#include <unistd.h>  
#include <gnutls/gnutls.h>  
#define SA struct sockaddr  
 
/* Connects to the peer and returns a socket  
* descriptor.  
*/  
int  
tcp_connect (void)  
{  
  const char *PORT = "5556";  
  const char *SERVER = "127.0.0.1";  
  int err, sd;  
  struct sockaddr_in sa;  
 
  /* connects to server  
   */  
  sd = socket (AF_INET, SOCK_STREAM, 0);  
 
  memset (&sa, '\0', sizeof (sa));  
  sa.sin_family = AF_INET;  
  sa.sin_port = htons (atoi (PORT));  
  inet_pton (AF_INET, SERVER, &sa.sin_addr);  
 
  err = connect (sd, (SA *) & sa, sizeof (sa));  
  if (err < 0)  
    {  
      fprintf (stderr, "Connect error\n");  
      exit (1);  
    }  
 
  return sd;  
}  
 
/* closes the given socket descriptor.  
*/  
void  
tcp_close (int sd)  
{  
  shutdown (sd, SHUT_RDWR);    /* no more receptions */  
  close (sd);  
}  

#define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);}  
#define MAX_BUF 1024  
#define PORT 5556        /* listen to 5556 port */  
#define DH_BITS 1024  
 
/* These are global */  
gnutls_anon_server_credentials_t anoncred;  
 
gnutls_session_t  
initialize_tls_session (void)  
{  
  gnutls_session_t session;  
  const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };  
 
  gnutls_init (&session, GNUTLS_SERVER);  
 
  /* avoid calling all the priority functions, since the defaults  
   * are adequate.  
   */  
  gnutls_set_default_priority (session);  
  gnutls_kx_set_priority (session, kx_prio);  
 
  gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);  
 
  gnutls_dh_set_prime_bits (session, DH_BITS);  
 
  return session;  
}  
 
static gnutls_dh_params_t dh_params;  
 
static int  
generate_dh_params (void)  
{  
 
  /* Generate Diffie Hellman parameters - for use with DHE  
   * kx algorithms. These should be discarded and regenerated  
   * once a day, once a week or once a month. Depending on the  
   * security requirements.  
   */  
  gnutls_dh_params_init (&dh_params);  
  gnutls_dh_params_generate2 (dh_params, DH_BITS);  
 
  return 0;  
}  
 
int  
main (void)  
{  
  int err, listen_sd, i;  
  int sd, ret;  
  struct sockaddr_in sa_serv;  
  struct sockaddr_in sa_cli;  
  int client_len;  
  char topbuf[512];  
  gnutls_session_t session;  
  char buffer[MAX_BUF + 1];  
  int optval = 1;  
 
  /* this must be called once in the program  
   */  
  gnutls_global_init ();  
 
  gnutls_anon_allocate_server_credentials (&anoncred);  
 
  generate_dh_params ();  
 
  gnutls_anon_set_server_dh_params (anoncred, dh_params);  
 
  /* Socket operations  
   */  
  listen_sd = socket (AF_INET, SOCK_STREAM, 0);  
  SOCKET_ERR (listen_sd, "socket");  
 
  memset (&sa_serv, '\0', sizeof (sa_serv));  
  sa_serv.sin_family = AF_INET;  
  sa_serv.sin_addr.s_addr = INADDR_ANY;  
  sa_serv.sin_port = htons (PORT);    /* Server Port number */  
 
  setsockopt (listen_sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (int));  
 
  err = bind (listen_sd, (SA *) & sa_serv, sizeof (sa_serv));  
  SOCKET_ERR (err, "bind");  
  err = listen (listen_sd, 1024);  
  SOCKET_ERR (err, "listen");  
 
  printf ("Server ready. Listening to port '%d'.\n\n", PORT);  
 
  client_len = sizeof (sa_cli);  
  for (;;)  
    {  
      session = initialize_tls_session ();  
 
      sd = accept (listen_sd, (SA *) & sa_cli, &client_len);  
 
      printf ("- connection from %s, port %d\n",  
          inet_ntop (AF_INET, &sa_cli.sin_addr, topbuf,  
             sizeof (topbuf)), ntohs (sa_cli.sin_port));  
 
      gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);  
      ret = gnutls_handshake (session);  
      if (ret < 0)  
    {  
      close (sd);  
      gnutls_deinit (session);  
      fprintf (stderr, "*** Handshake has failed (%s)\n\n",  
           gnutls_strerror (ret));  
      continue;  
    }  
      printf ("- Handshake was completed\n");  
 
      /* see the Getting peer's information example */  
      /* print_info(session); */  
 
      i = 0;  
      for (;;)  
    {  
      memset (buffer, 0, MAX_BUF + 1);  
      ret = gnutls_record_recv (session, buffer, MAX_BUF);  
 
      if (ret == 0)  
        {  
          printf ("\n- Peer has closed the GNUTLS connection\n");  
          break;  
        }  
      else if (ret < 0)  
        {  
          fprintf (stderr, "\n*** Received corrupted "  
               "data(%d). Closing the connection.\n\n", ret);  
          break;  
        }  
      else if (ret > 0)  
        {  
          /* echo data back to the client  
           */  
          gnutls_record_send (session, buffer, strlen (buffer));  
        }  
    }  
      printf ("\n");  
      /* do not wait for the peer to close the connection.  
       */  
      gnutls_bye (session, GNUTLS_SHUT_WR);  
 
      close (sd);  
      gnutls_deinit (session);  
 
    }  
  close (listen_sd);  
 
  gnutls_anon_free_server_credentials (anoncred);  
 
  gnutls_global_deinit ();  
 
  return 0;  
 
}  
